package org.springblade.modules.admin.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.otter.canal.protocol.CanalEntry;
import lombok.extern.slf4j.Slf4j;
import org.springblade.modules.admin.entity.*;
import org.springblade.modules.admin.service.BuildingService;
import org.springblade.modules.admin.service.CanalClientService;
import org.springblade.modules.admin.service.CanalLogService;
import org.springblade.modules.admin.vo.TlwEstateCompanyVO;
import org.springblade.modules.admin.vo.tlw.TlwBuildingVO;
import org.springblade.modules.admin.vo.tlw.TlwElevatorEstateUserVO;
import org.springblade.modules.admin.vo.tlw.TlwElevatorVO;
import org.springblade.modules.system.entity.Tenant;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.service.ITenantService;
import org.springblade.modules.system.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Date 15:23 2023/5/29
 * @Description {
 *   Canal Client
 * }
 * @Author lsay
 **/
@Service
@Slf4j
public class CanalClientServiceImpl implements CanalClientService {


	/**
	 * 项目表名
	 */
	private static final String BLADE_BUILDING = "blade_building";
	/**
	 * 电梯主表名
	 */
	private static final String BLADE_ELEVATOR = "blade_elevator";
	/**
	 * 电梯详情表名
	 */
	private static final String BLADE_ELEVATOR_DETAIL = "blade_elevator_detail";
	/**
	 * 租户表名（物业公司）
	 */
	private static final String BLADE_TENANT = "blade_tenant";
	/**
	 * 物业电梯表名
	 */
	private static final String BLADE_ESTATE_ELEVATOR = "blade_estate_elevator";
	/**
	 * 物业人员表名
	 */
	private static final String BLADE_ESTATE_ELEVATOR_USER = "blade_estate_elevator_user";
	/**
	 * 人员表名
	 */
	private static final String BLADE_USER = "blade_user";

	private static final String DELETE = "delete";
	private static final String UPDATE = "update";

	@Value("${ems.url}")
	private String emsUrl;

	@Value("${tlw.timeout}")
	private Integer timeout;

	@Autowired
	private IUserService userService;
	@Autowired
	private BuildingService buildingService;
	@Autowired
	private ITenantService tenantService;
	@Autowired
	private CanalLogService canalLogService;

	/**
	 * 监听更新操作的处理
	 * @param tableName
	 * @param rowChange
	 */
    public void buildingUpdate(String tableName, CanalEntry.RowChange rowChange) {
		List<JSONObject> jsonObjects = this.toJsonList(rowChange.getRowDatasList());
		List<Building> afterList = jsonObjects.stream().map(e -> JSONObject.parseObject(String.valueOf(e),Building.class)).collect(Collectors.toList());
		List<Building> deleteAfterList = afterList.stream().filter(e -> ObjectUtil.isEmpty(e.getIsDeleted())).collect(Collectors.toList());
		List<Building> updateAfterList = afterList.stream().filter(e -> ObjectUtil.isNotEmpty(e.getIsDeleted())).collect(Collectors.toList());
		Map<String,List<Building>> groupMap = new HashMap<>(2);
		if(ObjectUtil.isNotEmpty(deleteAfterList)){
			groupMap.put(DELETE,deleteAfterList);
		}
		if(ObjectUtil.isNotEmpty(updateAfterList)){
			groupMap.put(UPDATE,updateAfterList);
		}

		groupMap.forEach((k,v) -> {
			Map<String,Object> requestMap = new HashMap<>(2);
			requestMap.put("type",0);
			if(DELETE.equals(k)){
				requestMap.put("type",1);
			}
			List<TlwBuildingVO> buildingVOS = buildingService.selectTlwBuilding(v.stream().map(Building::getId).distinct().collect(Collectors.toList()));
			requestMap.put("body",buildingVOS);
			String url = "/ems/v1/syncData/syncBuilding";
			log.info("==================== RequestBody: {} 请求结果 ====================",JSONObject.toJSONString(requestMap));
			String resultBody = HttpUtil.createPost(emsUrl+url).body(JSONObject.toJSONString(requestMap)).execute().body();
			log.info("==================== Response: {} 请求结果 ====================",resultBody);
			JSONObject resultJson = JSONObject.parseObject(resultBody);
			if (!"200".equals(String.valueOf(resultJson.get("code")))) {
				List<CanalLog> canalLogList = new ArrayList<>();
				v.forEach(u -> {
					CanalLog canalLog = new CanalLog();
					canalLog.setParamKey(u.getId());
					canalLog.setParamName(tableName);
					canalLog.setType(this.getLogType(tableName));
					canalLogList.add(canalLog);
				});
				canalLogService.saveBatch(canalLogList);
			}
		});
    }

	/**
	 * 监听更新操作的处理
	 * @param tableName
	 * @param rowChange
	 */
	public void elevatorUpdate(String tableName, CanalEntry.RowChange rowChange) {

		List<JSONObject> jsonObjects = this.toJsonList(rowChange.getRowDatasList());
		List<Long> elevatorIds;
		if(tableName.equals(BLADE_ELEVATOR)){
			List<Elevator> elevators = jsonObjects.stream().map(e -> JSONObject.parseObject(String.valueOf(e),Elevator.class)).collect(Collectors.toList());
			elevatorIds = elevators.stream().map(Elevator::getId).distinct().collect(Collectors.toList());
		}else if(tableName.equals(BLADE_ELEVATOR_DETAIL)) {
			List<ElevatorDetail> elevators = jsonObjects.stream().map(e -> JSONObject.parseObject(String.valueOf(e),ElevatorDetail.class)).collect(Collectors.toList());
			elevatorIds = elevators.stream().map(ElevatorDetail::getElevatorId).distinct().collect(Collectors.toList());
		}else {
			List<EstateElevator> elevators = jsonObjects.stream().map(e -> JSONObject.parseObject(String.valueOf(e),EstateElevator.class)).collect(Collectors.toList());
			elevatorIds = elevators.stream().map(EstateElevator::getElevatorId).distinct().collect(Collectors.toList());
		}
		List<TlwElevatorVO> tlwElevatorVOS = buildingService.selectTlwElevator(elevatorIds);
		List<TlwElevatorVO> deleteAfterList = tlwElevatorVOS.stream().filter(e -> ObjectUtil.isEmpty(e.getIsDeleted())).collect(Collectors.toList());
		List<TlwElevatorVO> updateAfterList = tlwElevatorVOS.stream().filter(e -> ObjectUtil.isNotEmpty(e.getIsDeleted())).collect(Collectors.toList());
		Map<String,List<TlwElevatorVO>> groupMap = new HashMap<>(2);
		if(ObjectUtil.isNotEmpty(deleteAfterList)){
			groupMap.put(DELETE,deleteAfterList);
		}
		if(ObjectUtil.isNotEmpty(updateAfterList)){
			groupMap.put(UPDATE,updateAfterList);
		}

		groupMap.forEach((k,v) -> {

			Map<String,Object> requestMap = new HashMap<>(2);
			requestMap.put("type",0);
			if(DELETE.equals(k)){
				requestMap.put("type",1);
			}
			requestMap.put("body",v);
			String url = "/ems/v1/syncData/syncElevator";
			log.info("==================== RequestBody: {} 请求结果 ====================",JSONObject.toJSONString(requestMap));
			String resultBody = HttpUtil.createPost(emsUrl+url).body(JSONObject.toJSONString(requestMap)).execute().body();
			log.info("==================== Response: {} 请求结果 ====================",resultBody);
			JSONObject resultJson = JSONObject.parseObject(resultBody);
			if (!"200".equals(String.valueOf(resultJson.get("code")))) {
				List<CanalLog> canalLogList = new ArrayList<>();
				v.forEach(u -> {
					CanalLog canalLog = new CanalLog();
					canalLog.setParamKey(u.getElevatorId());
					canalLog.setParamName(tableName);
					canalLog.setType(this.getLogType(tableName));
					canalLogList.add(canalLog);
				});
				canalLogService.saveBatch(canalLogList);
			}

		});
	}

	/**
	 * 监听更新操作的处理
	 * @param tableName
	 * @param rowChange
	 */
	public void estateCompanyUpdate(String tableName, CanalEntry.RowChange rowChange) {

		List<JSONObject> jsonObjects = this.toJsonList(rowChange.getRowDatasList());
		List<Tenant> afterList = jsonObjects.stream().map(e -> JSONObject.parseObject(String.valueOf(e),Tenant.class)).collect(Collectors.toList());
		List<Tenant> deleteAfterList = afterList.stream().filter(e -> ObjectUtil.isEmpty(e.getIsDeleted())).collect(Collectors.toList());
		List<Tenant> updateAfterList = afterList.stream().filter(e -> ObjectUtil.isNotEmpty(e.getIsDeleted())).collect(Collectors.toList());
		Map<String,List<Tenant>> groupMap = new HashMap<>(2);
		if(ObjectUtil.isNotEmpty(deleteAfterList)){
			groupMap.put(DELETE,deleteAfterList);
		}
		if(ObjectUtil.isNotEmpty(updateAfterList)){
			groupMap.put(UPDATE,updateAfterList);
		}

		groupMap.forEach((k,v) -> {
			Map<String,Object> requestMap = new HashMap<>(2);
			requestMap.put("type",0);
			if(DELETE.equals(k)){
				requestMap.put("type",1);
			}
			List<TlwEstateCompanyVO> tenantMapList = v.stream().map(e -> {
				TlwEstateCompanyVO companyVO = new TlwEstateCompanyVO();
				companyVO.setEstateCompanyId(e.getId());
				companyVO.setEstateCompanyName(e.getTenantName());
				return companyVO;
			}).collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(TlwEstateCompanyVO::getEstateCompanyId))),ArrayList::new));
			requestMap.put("body",tenantMapList);
			String url = "/ems/v1/syncData/syncEstateCompany";
			log.info("==================== RequestBody: {} 请求结果 ====================",JSONObject.toJSONString(requestMap));
			String resultBody = HttpUtil.createPost(emsUrl+url).body(JSONObject.toJSONString(requestMap)).execute().body();
			log.info("==================== Response: {} 请求结果 ====================",resultBody);
			JSONObject resultJson = JSONObject.parseObject(resultBody);
			if (!"200".equals(String.valueOf(resultJson.get("code")))) {
				List<CanalLog> canalLogList = new ArrayList<>();
				v.forEach(u -> {
					CanalLog canalLog = new CanalLog();
					canalLog.setParamKey(u.getId());
					canalLog.setParamName(tableName);
					canalLog.setType(this.getLogType(tableName));
					canalLogList.add(canalLog);
				});
				canalLogService.saveBatch(canalLogList);
			}
		});
	}

	/**
	 * 监听更新操作的处理
	 * @param tableName
	 * @param rowChange
	 */
	public void estateElevatorUserUpdate(String tableName, CanalEntry.RowChange rowChange) {

		List<JSONObject> jsonObjects = this.toJsonList(rowChange.getRowDatasList());
		List<EstateElevatorUser> afterList = jsonObjects.stream().map(e -> JSONObject.parseObject(String.valueOf(e),EstateElevatorUser.class)).collect(Collectors.toList());
		List<EstateElevatorUser> deleteAfterList = afterList.stream().filter(e -> ObjectUtil.isEmpty(e.getIsDeleted())).collect(Collectors.toList());
		List<EstateElevatorUser> updateAfterList = afterList.stream().filter(e -> ObjectUtil.isNotEmpty(e.getIsDeleted())).collect(Collectors.toList());
		Map<String,List<EstateElevatorUser>> groupMap = new HashMap<>(2);
		if(ObjectUtil.isNotEmpty(deleteAfterList)){
			groupMap.put(DELETE,deleteAfterList);
		}
		if(ObjectUtil.isNotEmpty(updateAfterList)){
			groupMap.put(UPDATE,updateAfterList);
		}

		groupMap.forEach((k,v) -> {

			Map<String,Object> requestMap = new HashMap<>(2);
			requestMap.put("type",0);
			if(DELETE.equals(k)){
				requestMap.put("type",1);
			}
			List<TlwElevatorEstateUserVO> userVOS = v.stream().map(e -> {
				User user = userService.getById(e.getUserId());
				Tenant tenant = tenantService.getByTenantId(e.getTenantId());
				TlwElevatorEstateUserVO elevatorEstateUserVO = new TlwElevatorEstateUserVO();
				elevatorEstateUserVO.setElevatorId(e.getElevatorId());
				elevatorEstateUserVO.setUserId(e.getUserId());
				elevatorEstateUserVO.setEstateCompanyId(tenant.getId());
				elevatorEstateUserVO.setUserName(user.getRealName());
				elevatorEstateUserVO.setPhone(user.getPhone());
				return elevatorEstateUserVO;
			}).collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(TlwElevatorEstateUserVO::getUserId))),ArrayList::new));
			requestMap.put("body",userVOS);
			String url = "/ems/v1/syncData/syncEstateUserRelation";
			log.info("==================== RequestBody: {} 请求结果 ====================",JSONObject.toJSONString(requestMap));
			String resultBody = HttpUtil.createPost(emsUrl+url).body(JSONObject.toJSONString(requestMap)).execute().body();
			log.info("==================== Response: {} 请求结果 ====================",resultBody);
			JSONObject resultJson = JSONObject.parseObject(resultBody);
			if (!"200".equals(String.valueOf(resultJson.get("code")))) {
				List<CanalLog> canalLogList = new ArrayList<>();
				v.forEach(u -> {
					CanalLog canalLog = new CanalLog();
					canalLog.setParamKey(u.getElevatorId());
					canalLog.setParamName(tableName);
					canalLog.setType(this.getLogType(tableName));
					canalLogList.add(canalLog);
				});
				canalLogService.saveBatch(canalLogList);
			}
		});
	}

	/**
	 * 监听更新操作的处理
	 * @param tableName
	 * @param rowChange
	 */
	public void userUpdate(String tableName, CanalEntry.RowChange rowChange) {

		List<JSONObject> jsonObjects = this.toJsonList(rowChange.getRowDatasList());
		List<User> afterList = jsonObjects.stream().map(e -> JSONObject.parseObject(String.valueOf(e),User.class)).collect(Collectors.toList());
		List<User> deleteAfterList = afterList.stream().filter(e -> ObjectUtil.isEmpty(e.getIsDeleted())).collect(Collectors.toList());
		List<User> updateAfterList = afterList.stream().filter(e -> ObjectUtil.isNotEmpty(e.getIsDeleted())).collect(Collectors.toList());
		Map<String,List<User>> groupMap = new HashMap<>(2);
		if(ObjectUtil.isNotEmpty(deleteAfterList)){
			groupMap.put(DELETE,deleteAfterList);
		}
		if(ObjectUtil.isNotEmpty(updateAfterList)){
			groupMap.put(UPDATE,updateAfterList);
		}
		groupMap.forEach((k,v) -> {

			Map<String,Object> requestMap = new HashMap<>(2);
			requestMap.put("type",0);
			if(DELETE.equals(k)){
				requestMap.put("type",1);
			}
			List<TlwElevatorEstateUserVO> userVOS = v.stream().map(e -> {
				TlwElevatorEstateUserVO userVO = new TlwElevatorEstateUserVO();
				userVO.setUserId(e.getId());
				userVO.setUserName(e.getRealName());
				userVO.setPhone(e.getPhone());
				return userVO;
			}).collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(TlwElevatorEstateUserVO::getUserId))),ArrayList::new));
			requestMap.put("body",userVOS);
			String url = "/ems/v1/syncData/syncEstateUser";
			log.info("==================== RequestBody: {} 请求结果 ====================",JSONObject.toJSONString(requestMap));
			String resultBody = HttpUtil.createPost(emsUrl+url).body(JSONObject.toJSONString(requestMap)).execute().body();
			log.info("==================== Response: {} 请求结果 ====================",resultBody);
			JSONObject resultJson = JSONObject.parseObject(resultBody);
			if (!"200".equals(String.valueOf(resultJson.get("code")))) {
				List<CanalLog> canalLogList = new ArrayList<>();
				v.forEach(u -> {
					CanalLog canalLog = new CanalLog();
					canalLog.setParamKey(u.getId());
					canalLog.setParamName(tableName);
					canalLog.setType(this.getLogType(tableName));
					canalLogList.add(canalLog);
				});
				canalLogService.saveBatch(canalLogList);
			}
		});
	}

	private String getEventType(CanalEntry.EventType eventType) {
		switch (eventType.getNumber()){
			case CanalEntry.EventType.INSERT_VALUE:
				return "新增";
			case CanalEntry.EventType.UPDATE_VALUE:
				return "更新";
			case CanalEntry.EventType.DELETE_VALUE:
				return "删除";
			default:return "更新";
		}
	}

	/**
	 * 转 JSON
	 * @param afterColumnsList
	 * @return
	 */
	private JSONObject toJson(List<CanalEntry.Column> afterColumnsList) {
		JSONObject jsonObject = new JSONObject();
		afterColumnsList.forEach(e -> jsonObject.put(e.getName(),e.getValue()));
		return jsonObject;
	}

	/**
	 * 转 JSON
	 * @param columnsList
	 * @return
	 */
	private List<JSONObject> toJsonList(List<CanalEntry.RowData> columnsList) {
		return columnsList.stream().map(e -> {
			JSONObject jsonObject = new JSONObject();
			e.getAfterColumnsList().forEach(j -> jsonObject.put(j.getName(),j.getValue()));
			return jsonObject;
		}).collect(Collectors.toList());
	}

	/**
	 * 获取类型
	 * @param tableName
	 * @return
	 */
	private Integer getLogType(String tableName) {
		switch (tableName) {
			case BLADE_BUILDING:
				return 1;
			case BLADE_ELEVATOR:
			case BLADE_ELEVATOR_DETAIL:
			case BLADE_ESTATE_ELEVATOR:
			case BLADE_ESTATE_ELEVATOR_USER:
				return 2;
			case BLADE_TENANT:
				return 3;
			case BLADE_USER:
				return 4;
		}
		return 0;
	}

	@Override
	@Async
	public void tlwSync(String tableName, CanalEntry.RowChange rowChange) {
		switch (tableName) {
			case BLADE_BUILDING:
				this.buildingUpdate(tableName,rowChange);
				break;
			case BLADE_ELEVATOR:
			case BLADE_ELEVATOR_DETAIL:
			case BLADE_ESTATE_ELEVATOR:
				this.elevatorUpdate(tableName,rowChange);
				break;
			case BLADE_ESTATE_ELEVATOR_USER:
				this.estateElevatorUserUpdate(tableName,rowChange);
				break;
			case BLADE_TENANT:
				this.estateCompanyUpdate(tableName,rowChange);
				break;
			case BLADE_USER:
				this.userUpdate(tableName,rowChange);
				break;
		}
	}

//	@UpdateListenPoint
//	public void onEventUpdateData(CanalMsg canalMsg, CanalEntry.RowChange rowChange) {
//		System.out.println("======================注解方式（更新数据操作）==========================");
//		List<CanalEntry.RowData> rowDatasList = rowChange.getRowDatasList();
//		for (CanalEntry.RowData rowData : rowDatasList) {
//
//			String sql = "use " + canalMsg.getSchemaName() + ";\n";
//			StringBuffer updates = new StringBuffer();
//			StringBuffer conditions = new StringBuffer();
//			rowData.getAfterColumnsList().forEach((c) -> {
//				if (c.getIsKey()) {
//					conditions.append(c.getName() + "='" + c.getValue() + "'");
//				} else {
//					updates.append(c.getName() + "='" + c.getValue() + "',");
//				}
//			});
//			sql += "UPDATE " + canalMsg.getTableName() + " SET " + updates.substring(0, updates.length() - 1) + " WHERE " + conditions;
//			System.out.println(sql);
//		}
//		System.out.println("\n======================================================");
//	}

	/**
	 * 监听更新操作的处理
	 * @param eventType
	 * @param rowData
	 */
//	@ListenPoint(destination = "example", schema = "sida_maintain", table = {"blade_building", BLADE_ELEVATOR ,BLADE_ELEVATOR_ADDRESS}, eventType = CanalEntry.EventType.UPDATE)
//	public void update(CanalEntry.EventType eventType, CanalEntry.RowData rowData,CanalEntry.Header header) {
//		System.out.println("更新操作");
//		rowData.getBeforeColumnsList().forEach((c) -> System.err.println("更新前数据: " + c.getName() + " :: " + c.getValue()));
//		User user = userService.getById(rowData.getBeforeColumns(0).getValue());
//
//		rowData.getAfterColumnsList().forEach((c) -> System.err.println("更新后数据: " + c.getName() + " :: " + c.getValue()));
//
//	}

}
